﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright company="DHGMS Solutions" file="Email.cs">
//   2004-2012 DHGMS Solutions. Some Rights Reserved. Licensed under GNU General Public License version 2 (GPLv2)
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Dhgms.TplHelper.Model.Provider.Job
{
    using System;
    using System.Linq;
    using System.Net.Mail;
    using System.Text;

    using Dhgms.DataManager.Model.Helper;
    using Dhgms.TplHelper.Model.Info.JobResult;

    using NLog.Targets;

    /// <summary>
    /// Provider for emailing out the error report
    /// </summary>
    /// <typeparam name="TJobResultClass">
    /// </typeparam>
    public abstract class Email<TJobResultClass> : Base<TJobResultClass>
        where TJobResultClass : Base, new()
    {
        #region Properties

        /// <summary>
        /// Primary Receiver Of Error Emails
        /// </summary>
        protected MailAddress ErrorRecipient { get; set; }

        /// <summary>
        /// Hostname used to send the email
        /// </summary>
        protected string HostName { get; set; }

        /// <summary>
        /// Recipients who will receive the email
        /// </summary>
        protected MailAddressCollection Recipients { get; set; }

        /// <summary>
        /// Sender of the email
        /// </summary>
        protected MailAddress Sender { get; set; }

        /// <summary>
        /// Whether the sucess emails are html
        /// </summary>
        protected bool SuccessEmailIsHtml { get; set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Handles sending of error information to different mediums
        /// </summary>
        /// <param name="programGuid">
        /// Unique GUID used to identify program
        /// </param>
        /// <param name="programName">
        /// Friendly name of program
        /// </param>
        /// <param name="e">
        /// Exception message
        /// </param>
        public override void OnJobFailure(Guid programGuid, string programName, Exception e)
        {
            this.DoDetailedFailureInformation(programGuid, programName, e);

            this.DoBasicFailureInformation(programGuid, programName);
        }

        /// <summary>
        /// Notify the provider of a job start
        /// </summary>
        /// <param name="jobGuid">
        /// Unique ID of the job
        /// </param>
        public override void OnJobStart(Guid jobGuid)
        {
        }

        /// <summary>
        /// Handles sending out the result information
        /// </summary>
        /// <param name="jobGuid">
        /// Unique GUID used to identify program
        /// </param>
        /// <param name="jobName">
        /// Friendly name of program
        /// </param>
        /// <param name="taskResult">
        /// Run results of task
        /// </param>
        public override void OnJobSucess(Guid jobGuid, string jobName, TJobResultClass taskResult)
        {
            // get groups of recipients
            // check each groups options
            // get list of recipients for the group
            // generate and send email
            MailAddressCollection bcc = this.Recipients;

            string subject = jobName + ": Completed";
            var body = new StringBuilder(this.OnGetBody(taskResult));
            this.AppendLoggingDetails(body);

            this.SendEmail(bcc, subject, body.ToString(), this.SuccessEmailIsHtml);
        }

        /// <summary>
        /// Handles the sending of a task failure notification, if required
        /// </summary>
        /// <param name="taskGuid">
        /// The GUID relating to the task
        /// </param>
        /// <param name="e">
        /// Exception message
        /// </param>
        public override void OnTaskFailure(Guid taskGuid, Exception e)
        {
        }

        /// <summary>
        /// Handles the sending of a task start notification, if required
        /// </summary>
        /// <param name="taskGuid">
        /// The GUID relating to the task
        /// </param>
        public override void OnTaskStart(Guid taskGuid)
        {
        }

        /// <summary>
        /// Handles the sending of a task completion notification, if required
        /// </summary>
        /// <param name="taskGuid">
        /// The GUID relating to the task
        /// </param>
        public override void OnTaskSucess(Guid taskGuid)
        {
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets the body of the email
        /// </summary>
        /// <param name="taskResult">
        /// The task Result.
        /// </param>
        /// <returns>
        /// body of the email
        /// </returns>
        protected abstract string OnGetBody(TJobResultClass taskResult);

        /// <summary>
        /// Sends basic failure information to those who don't need to know the
        /// gorey details
        /// </summary>
        /// <param name="programGuid">
        /// The program Guid.
        /// </param>
        /// <param name="jobName">
        /// The job Name.
        /// </param>
        private void DoBasicFailureInformation(Guid programGuid, string jobName)
        {
            try
            {
                MailAddressCollection bcc = this.Recipients;

                // we don't want to be emailing anyone who gets the detailed email
                // we match by email address in case the display name is different
                for (var i = 0; i < bcc.Count; i++)
                {
                    var recipient = bcc[i];
                    if (!recipient.Address.Equals(this.ErrorRecipient.Address))
                    {
                        continue;
                    }

                    bcc.Remove(recipient);
                    break;
                }

                string subject = jobName + ": Failed";
                var body = new StringBuilder();
                body.AppendLine(
                    "The job has failed.  This is for information purposes only, a detailed error message has been sent to the system operator.");
                body.AppendLine(string.Empty);
                body.AppendLine("Program Guid: " + programGuid);

                this.SendEmail(bcc, subject, body.ToString(), false);
            }
                
                // ReSharper disable RedundantEmptyFinallyBlock
            finally
            {
            }

            // ReSharper restore RedundantEmptyFinallyBlock
        }

        /// <summary>
        /// Sends the exception information to those who need to know
        /// and possibly fix it
        /// </summary>
        /// <param name="programGuid">
        /// The program Guid.
        /// </param>
        /// <param name="programName">
        /// The program Name.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void DoDetailedFailureInformation(Guid programGuid, string programName, Exception e)
        {
            try
            {
                string subject = programName + ": Fatal Exception";

                var body = new StringBuilder();
                body.AppendLine(e.ToString());
                body.AppendLine(string.Empty);

                try
                {
                    this.AppendLoggingDetails(body);
                }
                // ReSharper disable EmptyGeneralCatchClause
                catch
                // ReSharper restore EmptyGeneralCatchClause
                {
                }

                body.AppendLine("Program Guid: " + programGuid);

                var bcc = new MailAddressCollection { this.ErrorRecipient };

                this.SendEmail(bcc, subject, body.ToString(), false);
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch
            // ReSharper restore EmptyGeneralCatchClause
            {
            }
        }

        private void AppendLoggingDetails(StringBuilder body)
        {
            var loggingTarget = NLog.LogManager.Configuration.AllTargets.FirstOrDefault(x => x as MemoryTarget != null) as MemoryTarget;
            if (loggingTarget == null)
            {
                return;
            }

            body.AppendLine("<h3>Log output:</h3>");
            body.AppendLine("<table>");

            foreach (var logLine in loggingTarget.Logs)
            {
                body.AppendLine(string.Format("<tr><td>{0}</td></tr>", System.Net.WebUtility.HtmlEncode(logLine).Replace("|", "</td><td>")));
            }

            body.AppendLine("</table>");

            body.AppendLine(string.Empty);
        }

        /// <summary>
        /// Wrapper to send the email
        /// </summary>
        /// <param name="bcc">
        /// </param>
        /// <param name="subject">
        /// </param>
        /// <param name="body">
        /// </param>
        /// <param name="isHtml">
        /// </param>
        private void SendEmail(MailAddressCollection bcc, string subject, string body, bool isHtml)
        {
            EmailExtensions.SendEmail(this.HostName, this.Sender, null, null, bcc, subject, body, null, isHtml);
        }

        #endregion
    }
}